home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 October: Mac OS SDK / Dev.CD Oct 97 SDK1.toast / Development Kits (Disc 1) / QuickDraw GX / Programming Stuff / Sample Code / Printing Samples / Applications… / QuickDraw GX Aware Sample ƒ / Simple Sample GX ƒ / printing.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-03-20  |  16.6 KB  |  631 lines  |  [TEXT/MMCC]

  1. /*********************************************************************
  2.  
  3.     Printing.c
  4.     
  5.     This file contains the printing code for the QuickDraw GX aware
  6.     sample, "Simple Sample GX."
  7.     
  8.     Additional info can be found in the related develop #19 article,
  9.     "Adding QuickDraw GX Printing to QuickDraw Applications."
  10.  
  11.     Dave Hersey, Apple Developer Technical Support.
  12.     
  13.     ——————— Edit Trail ———————
  14.     
  15.     coughed up:                                        1/22/94  - dmh
  16.     cleaned up for 2nd draft of develop article:    3/10/94  - dmh
  17.     cleaned up for final:                            4/14/94  - dmh
  18.     build descriptors for ppc                       8/17/94  - nick
  19.     
  20. *********************************************************************/
  21.  
  22. #include "Simple Sample.h"
  23.  
  24.  
  25. /************************************************************
  26.   MyPrintDocument - This routine displays the QuickDraw GX
  27.   or non-QuickDraw GX "Print" dialog, and then prints the
  28.   document.
  29.  
  30. *************************************************************/
  31.  
  32. OSErr MyPrintDocument(MyDocumentPtr whichDocument)
  33. {
  34.     OSErr                err = noErr;
  35.     gxEditMenuRecord    editMenuRec;
  36.     gxDialogResult        result;
  37.  
  38.     if (gGXIsPresent)
  39.     {
  40. /*
  41.     If QuickDraw GX is present, fill in the location of the application's
  42.     Edit menu items, enable/disable appropriate menu items, and display
  43.     the Print dialog.  If the user clicks the Print button, print using
  44.     QuickDraw GX.
  45. */
  46.         editMenuRec.editMenuID    = mEdit;
  47.         editMenuRec.cutItem        = iCut;
  48.         editMenuRec.copyItem    = iCopy;
  49.         editMenuRec.pasteItem    = iPaste;
  50.         editMenuRec.clearItem    = iClear;
  51.         editMenuRec.undoItem    = iUndo;
  52.     
  53.         MyAdjustMenusForPrintDialogs(true);
  54.         result = GXJobPrintDialog(whichDocument->documentJob, &editMenuRec);
  55.         MyAdjustMenusForPrintDialogs(false);
  56.  
  57.         if (result == gxOKSelected)
  58.             err = MyGXPrintLoop(whichDocument);
  59.     }
  60.     else
  61.     {
  62. /*
  63.     If QuickDraw GX is NOT present, open the printer driver, and put up the
  64.     old Print dialog.  If the user clicks the Print button, print using
  65.     the Printing Manager.
  66. */
  67.         PrOpen();
  68.         PrValidate(whichDocument->documentPrintHdl);
  69.         if (PrJobDialog(whichDocument->documentPrintHdl))
  70.             err = MyQDPrintLoop(whichDocument);    // Print using QuickDraw.
  71.         PrClose();
  72.     }
  73.  
  74.     return err;
  75. }
  76.  
  77.  
  78. /************************************************************
  79.   MyPrintOneCopy - This routine sets up job collection items
  80.   so that we'll print one copy of the passed document, then
  81.   it jumps into our printing routine.  This function is only
  82.   called when QuickDraw GX is running.
  83.  
  84. *************************************************************/
  85.  
  86. OSErr MyPrintOneCopy(MyDocumentPtr whichDocument)
  87. {
  88.     OSErr                    err;
  89.     Collection                jobCollection;
  90.     gxCopiesInfo            copiesInfo;
  91.     gxFileDestinationInfo    destInfo;
  92.     gxPageRangeInfo            pageRangeInfo;
  93.     Ptr                        oldCopiesInfo = nil, oldPageRangeInfo = nil, oldDestInfo = nil;
  94.     long                    oldCopiesSize, oldPageRangeInfoSize, oldDestInfoSize;
  95.  
  96. // Get the job collection and set it up to print one copy…
  97.  
  98.     jobCollection = GXGetJobCollection(whichDocument->documentJob);
  99.  
  100. // Set number of copies to 1.
  101.     
  102.     copiesInfo.copies = 1;
  103.     err = MyReplaceCollectionItem(&copiesInfo, sizeof(gxCopiesInfo),
  104.                                     gxCopiesTag, gxPrintingTagID,
  105.                                     jobCollection, &oldCopiesInfo, &oldCopiesSize);
  106.     nrequire(err, ReplaceCopies_error);
  107.  
  108. // Set page range to "all".
  109.  
  110.     pageRangeInfo.simpleRange.optionChosen = gxDefaultPageRange;
  111.     pageRangeInfo.minFromPage = 1;
  112.     pageRangeInfo.simpleRange.fromPage = 1;
  113.     pageRangeInfo.maxToPage = whichDocument->numPages;
  114.     pageRangeInfo.simpleRange.toPage = whichDocument->numPages;
  115.     pageRangeInfo.simpleRange.printAll = true;
  116.     err = MyReplaceCollectionItem(&pageRangeInfo, sizeof(gxPageRangeInfo),
  117.                                     gxPageRangeTag, gxPrintingTagID,
  118.                                     jobCollection, &oldPageRangeInfo, &oldPageRangeInfoSize);
  119.     nrequire(err, ReplacePageRange_error);
  120.  
  121. // Set destination to "printer".
  122.  
  123.     destInfo.toFile = false;
  124.     err = MyReplaceCollectionItem(&destInfo, sizeof(gxFileDestinationInfo),
  125.                                   gxFileDestinationTag, gxPrintingTagID,
  126.                                   jobCollection, &oldDestInfo, &oldDestInfoSize);
  127.     nrequire(err, ReplaceDestination_error);
  128.  
  129. // Print one copy of our document.
  130.  
  131.     err = MyGXPrintLoop(whichDocument);
  132.  
  133. /*
  134.     Restore original number of copies, page range, and output
  135.     destination in case anybody uses that info.
  136. */
  137.  
  138. ReplaceDestination_error:
  139.     MyReplaceCollectionItem(oldDestInfo, oldDestInfoSize,
  140.                             gxFileDestinationTag, gxPrintingTagID,
  141.                             jobCollection, nil, nil);
  142. ReplacePageRange_error:
  143.     MyReplaceCollectionItem(oldPageRangeInfo, oldPageRangeInfoSize,
  144.                             gxPageRangeTag, gxPrintingTagID,
  145.                             jobCollection, nil, nil);
  146. ReplaceCopies_error:
  147.     MyReplaceCollectionItem(oldCopiesInfo, oldCopiesSize,
  148.                               gxCopiesTag, gxPrintingTagID,
  149.                             jobCollection, nil, nil);
  150.  
  151. // Dispose of the pointers that MyReplaceCollectionItem created.
  152.  
  153.     if (oldCopiesInfo)
  154.         DisposePtr(oldCopiesInfo);
  155.  
  156.     if (oldPageRangeInfo)
  157.         DisposePtr(oldPageRangeInfo);
  158.  
  159.     if (oldDestInfo)
  160.         DisposePtr(oldDestInfo);
  161.  
  162.     return err;
  163. }
  164.  
  165.  
  166. /************************************************************
  167.   MyQDPrintLoop - This is our non-QuickDraw GX printing
  168.   routine.
  169.  
  170. *************************************************************/
  171.  
  172. OSErr MyQDPrintLoop(MyDocumentPtr whichDocument)
  173. {
  174.     OSErr            err = noErr;
  175.     THPrint            hPrint;
  176.     TPPrPort        printPort;
  177.     TPrStatus        theStatus;
  178.     short            copy, pg, iFstPage, iLstPage, oldCurPage;
  179.  
  180.     hPrint = whichDocument->documentPrintHdl;
  181.     oldCurPage = whichDocument->curPage;
  182.  
  183.     iFstPage = (*hPrint)->prJob.iFstPage;
  184.     if (iFstPage < 1)
  185.         iFstPage = 1;
  186.  
  187.     iLstPage = (*hPrint)->prJob.iLstPage;
  188.     if (iLstPage > whichDocument->numPages)
  189.         iLstPage = whichDocument->numPages;
  190.  
  191.     (*hPrint)->prJob.iFstPage = 1;
  192.     (*hPrint)->prJob.iLstPage = 9999;
  193.  
  194. /*
  195.     Loop for the number of copies we need to make, opening a
  196.     document and a page for each.
  197. */
  198.     for (copy = 1; !err && (copy <= (*hPrint)->prJob.iCopies); copy++)
  199.     {
  200.         printPort = PrOpenDoc(hPrint, nil, nil);
  201.  
  202.         if (!(err = PrError()))
  203.             for (pg = iFstPage; pg <= iLstPage; pg++)
  204.             {
  205.                 PrOpenPage(printPort, nil);
  206.  
  207.                 whichDocument->curPage = pg;
  208.                 MyDrawContents(whichDocument->documentWindow);
  209.         
  210.                 PrClosePage(printPort);
  211.             }
  212.  
  213.         PrCloseDoc(printPort);
  214.     }
  215.  
  216. // When finished printing, call PrPicFile (if necessary).
  217.  
  218.     if (!err) err = PrError();
  219.  
  220.     if (!err && ((*hPrint)->prJob.bJDocLoop == bSpoolLoop))
  221.         PrPicFile(hPrint, nil, nil, nil, &theStatus);
  222.     
  223.     whichDocument->curPage = oldCurPage;
  224.  
  225.     return err;
  226. }
  227.  
  228.  
  229. /************************************************************
  230.   MyGXPrintLoop - This is our QuickDraw GX printing
  231.   routine.
  232.  
  233. *************************************************************/
  234.  
  235. OSErr MyGXPrintLoop(MyDocumentPtr whichDocument)
  236. {
  237.     OSErr                err;
  238.     long                firstPage, lastPage, numPages, pg;
  239.     long                oldPage;
  240.     gxViewPort            printViewPort;
  241.     Point                patStretch = {1,1};
  242.     gxFormat            pageFormat;
  243.     Rect                everywhereRect;
  244.     MySpoolDataRec        spoolData;
  245.  
  246.     oldPage = whichDocument->curPage;
  247.  
  248. /*
  249.     Determine which pages the user selected to print.  If
  250.     the user specifies a page range that is greater than
  251.     the actual number of pages in the document, only print
  252.     those pages that are actually in the document. 
  253. */
  254.     GXGetJobPageRange(whichDocument->documentJob, &firstPage, &lastPage);
  255.     
  256.     if (lastPage > whichDocument->numPages)
  257.         lastPage = whichDocument->numPages;
  258.  
  259. /*
  260.     Calculate the total number of pages to print, and begin
  261.     printing if there are no errors.
  262. */
  263.     numPages = lastPage - firstPage +1;
  264.     err = GXGetJobError(whichDocument->documentJob);
  265.     nrequire(err, PageRangeError);
  266.  
  267.     GXStartJob(whichDocument->documentJob, whichDocument->documentTitle, numPages);
  268.     err = GXGetJobError(whichDocument->documentJob);
  269.     nrequire(err, StartJobFailed);
  270.  
  271. /*
  272.     Create a new viewport for printing, and set our translator rects
  273.     to "wide open" so they include all data we're drawing.  For each
  274.     page we print, call GXStartPage, draw, and call GXFinishPage.
  275. */
  276.     SetRect(&everywhereRect, 0, 0, 32767, 32767);
  277.     printViewPort = GXNewViewPort(gxScreenViewDevices);
  278.  
  279.     for (pg = firstPage; (err == noErr) && (pg <= lastPage); pg++)
  280.     {
  281.  
  282. // Get the page's format and start printing the page.
  283.  
  284.         pageFormat = whichDocument->pageFormat[pg -1];
  285.  
  286.         if (pageFormat == nil)
  287.             pageFormat = GXGetJobFormat(whichDocument->documentJob, 1);
  288.  
  289.         GXStartPage(whichDocument->documentJob,
  290.                     pg,
  291.                     pageFormat,
  292.                     1,
  293.                     &printViewPort);                                
  294.  
  295.         err = GXGetJobError(whichDocument->documentJob);
  296.  
  297. /*
  298.     If there were no errors, set up the Translator, draw the QuickDraw
  299.     data for the current page and remove the Translator.
  300.     
  301.     Note that, although it looks like it takes a GrafPtr,
  302.     GXInstallQDTranslator actually requires a pointer to a CGrafPort,
  303.     and will crash if you pass it a true GrafPtr.
  304. */
  305.         nrequire(err, StartPageFailed);
  306.         spoolData.printViewPort = printViewPort;
  307.         GXGetFormatDimensions(pageFormat, &spoolData.pageArea, nil);
  308.  
  309.         GXInstallQDTranslator(whichDocument->documentWindow,
  310.                               gxDefaultOptionsTranslation,
  311.                               &everywhereRect, &everywhereRect,
  312.                               patStretch, 
  313.                               NewgxShapeSpoolProc(MyPrintAShape),
  314.                               &spoolData);
  315.  
  316.         whichDocument->curPage = pg;
  317.         SetPort(whichDocument->documentWindow);
  318.         MyDrawContents(whichDocument->documentWindow);    
  319.         GXRemoveQDTranslator(whichDocument->documentWindow, nil);
  320.  
  321. // Finish the page.
  322.  
  323.         GXFinishPage(whichDocument->documentJob);
  324.     }
  325.  
  326. // Finish printing.
  327.  
  328. StartPageFailed:
  329.  
  330.     GXFinishJob(whichDocument->documentJob);
  331.     err = GXGetJobError(whichDocument->documentJob);
  332.         
  333.     GXDisposeViewPort(printViewPort);
  334.     whichDocument->curPage = oldPage;
  335.  
  336. StartJobFailed:
  337. PageRangeError:
  338.     return err;
  339. }
  340.  
  341.  
  342. /************************************************************
  343.   MyPrintAShape - This is a spool proc. for the translator
  344.   routines. In this routine, we simply draw each shape
  345.   we're passed (printing it).  You could also capture each
  346.   shape into one gxPicture shape, and then do one draw of
  347.   that afterwards.
  348.  
  349. *************************************************************/
  350.  
  351. OSErr MyPrintAShape(gxShape currentShape, long refCon)
  352. {
  353.     MySpoolDataPtr        spoolData;
  354.     gxShapeType            theShapeType;
  355.  
  356. /*
  357.     Don't waste time spooling the shape if it's being
  358.     drawn completely off the page.
  359. */
  360.     spoolData = (MySpoolDataPtr) refCon;
  361.     theShapeType = GXGetShapeType(currentShape);
  362.     
  363.     if ((theShapeType == gxEmptyType)   || 
  364.         (theShapeType == gxFullType)    || 
  365.         (theShapeType == gxPictureType) ||
  366.         (GXTouchesBoundsShape(&spoolData->pageArea, currentShape)))
  367.     {
  368.         GXSetShapeViewPorts(currentShape, 1, &spoolData->printViewPort);
  369.         GXDrawShape(currentShape);
  370.     }
  371.     
  372.     return (OSErr) GXGetGraphicsError(nil);
  373. }
  374.  
  375.  
  376. /************************************************************
  377.   MyDoPageSetup - This routine handles the "Page Setup"
  378.   dialog for QuickDraw GX and non-QuickDraw GX environments.
  379.  
  380. *************************************************************/
  381.  
  382. Boolean MyDoPageSetup(MyDocumentPtr whichDocument)
  383. {
  384.     Boolean                result;
  385.     gxDialogResult        dlgResult;
  386.     gxEditMenuRecord    editMenuRec;
  387.  
  388.     if (gGXIsPresent)                        // QuickDraw GX is being used.
  389.     {
  390. /*
  391.     Fill in the location of the application’s Edit menu items
  392.     and enable the appropriate menu items. 
  393. */
  394.         editMenuRec.editMenuID    = mEdit;
  395.         editMenuRec.cutItem        = iCut;
  396.         editMenuRec.copyItem    = iCopy;
  397.         editMenuRec.pasteItem    = iPaste;
  398.         editMenuRec.clearItem    = iClear;
  399.         editMenuRec.undoItem    = iUndo;
  400.  
  401.         MyAdjustMenusForPrintDialogs(true);
  402.         dlgResult = GXJobDefaultFormatDialog(whichDocument->documentJob, &editMenuRec);
  403.         MyAdjustMenusForPrintDialogs(false);
  404.         result = (dlgResult == gxOKSelected);
  405.     }
  406.     else                                    // QuickDraw GX is not being used.
  407.     {
  408.         PrOpen();
  409.         PrValidate(whichDocument->documentPrintHdl);
  410.         result = PrStlDialog(whichDocument->documentPrintHdl);
  411.         PrClose();
  412.     }
  413.  
  414.     return result;
  415. }
  416.  
  417.  
  418. /************************************************************
  419.   MyDoCustomPageSetup - This routine handles the "Custom
  420.   Page Setup" dialog for QuickDraw GX and is never called
  421.   unless QuickDraw GX is being used.
  422.  
  423. *************************************************************/
  424.  
  425. Boolean MyDoCustomPageSetup(MyDocumentPtr whichDocument)
  426. {
  427.     OSErr                    err = noErr;
  428.     gxDialogResult            result;
  429.     gxEditMenuRecord        editMenuRec;
  430.     gxFormat                pageFormat;
  431.     Boolean                    newPgFormat = false;
  432.  
  433. /*
  434.     Fill in the location of the application’s Edit menu items
  435.     and enable the appropriate menu items. 
  436. */
  437.     editMenuRec.editMenuID    = mEdit;
  438.     editMenuRec.cutItem        = iCut;
  439.     editMenuRec.copyItem    = iCopy;
  440.     editMenuRec.pasteItem    = iPaste;
  441.     editMenuRec.clearItem    = iClear;
  442.     editMenuRec.undoItem    = iUndo;
  443.  
  444.     MyAdjustMenusForPrintDialogs(true);
  445.     
  446. /*
  447.     If we have an existing page format, we'll modify that.
  448.     Otherwise, we'll need to create a new format and use that.
  449. */
  450.     if (whichDocument->pageFormat[whichDocument->curPage -1] != nil)
  451.         pageFormat = whichDocument->pageFormat[whichDocument->curPage -1];
  452.     else
  453.     {
  454.         pageFormat = GXNewFormat(whichDocument->documentJob);
  455.         newPgFormat = true;
  456.         err = GXGetJobError(whichDocument->documentJob);
  457.     }
  458.  
  459. // If no errors, display the format dialog.
  460.  
  461.     if (err == noErr)
  462.     {
  463.         result = GXFormatDialog(pageFormat, &editMenuRec, nil);
  464.  
  465.         switch (result)
  466.         {
  467.  
  468. /*
  469.     If the user selected "Remove", use the default job format
  470.     with this page.  For our application, we indicate this by
  471.     storing nil for the format reference in our structure.
  472.     
  473.     If "OK" was selected, store the new format with this page.
  474. */
  475.             case gxRevertSelected:
  476.                 GXDisposeFormat(pageFormat);
  477.                 pageFormat = nil;
  478.  
  479.             case gxOKSelected:
  480.                 whichDocument->pageFormat[whichDocument->curPage -1] = pageFormat;
  481.                 break;
  482.  
  483. /*
  484.     If the user selected "Cancel", dispose of our cloned copy
  485.     of the default job format, if we made one.
  486. */
  487.             case gxCancelSelected:
  488.                 if (newPgFormat) GXDisposeFormat(pageFormat);
  489.                 break;
  490.         }
  491.     }
  492.  
  493.     MyAdjustMenusForPrintDialogs(false);
  494.  
  495.     return newPgFormat;
  496. }
  497.  
  498.  
  499. /************************************************************
  500.   MyRepaginateDoc - This routine handles repagination of our
  501.   document.
  502.  
  503. *************************************************************/
  504.  
  505. void MyRepaginateDoc(MyDocumentPtr whichDocument)
  506. {
  507.     long            pageNum;
  508.     Rect            repaginateRect;
  509.     gxRectangle        pageArea, paperArea;
  510.     gxFormat        pageFormat;
  511.  
  512.     for (pageNum = 1; pageNum <= whichDocument->numPages; pageNum++)
  513.     {
  514.  
  515. /*
  516.     Repaginate our document using the format's page area
  517.     if QuickDraw GX is being used, or else the print
  518.     record's rPage.
  519. */
  520.         if (gGXIsPresent)                    // QuickDraw GX is being used.
  521.         {
  522.             pageFormat = whichDocument->pageFormat[pageNum -1];
  523.  
  524.             if (pageFormat == nil)
  525.                 pageFormat = GXGetJobFormat(whichDocument->documentJob, 1);
  526.             
  527.             GXGetFormatDimensions(pageFormat, &pageArea, &paperArea);
  528.  
  529.             SetRect(&repaginateRect,
  530.                     pageArea.left >>16,
  531.                     pageArea.top >>16,
  532.                     pageArea.right >>16,
  533.                     pageArea.bottom >>16);
  534.         }
  535.         else                                // QuickDraw GX isn't being used.
  536.             repaginateRect = (*whichDocument->documentPrintHdl)->prInfo.rPage;
  537.  
  538.     /*
  539.         Repaginate the document based on our printable area.
  540.         .
  541.         .
  542.         .
  543.     */
  544.  
  545.     }
  546. }
  547.  
  548.  
  549. /************************************************************
  550.   MyReplaceCollectionItem - This routine replaces a
  551.   collection item with the passed data.  If the oldData
  552.   pointer is not nil, the data that's being replaced is
  553.   returned in it.  (If the item doesn't already exist, then
  554.   a copy of the newData is returned instead.)  Note that the
  555.   oldData pointer is actually created in this routine.  You
  556.   just pass a pointer indicating where to store it (or nil
  557.   if you don't want the old data returned).
  558.  
  559. *************************************************************/
  560.  
  561. OSErr MyReplaceCollectionItem(void *newData, long collectSize,
  562.                               OSType collectType, long collectID,
  563.                               Collection whichCollection,
  564.                               Ptr *oldData, long *oldDataSize)
  565. {
  566.     OSErr    err;
  567.     long    index;
  568.  
  569. /*
  570.     If we're supposed to return the old data, get it.
  571.     If there is no old data, return a copy of the new data.
  572. */
  573.     if (oldData)
  574.     {
  575.         err = GetCollectionItemInfo(whichCollection,
  576.                                     collectType,
  577.                                     collectID,
  578.                                     dontWantIndex,
  579.                                     oldDataSize,
  580.                                     dontWantAttributes);
  581.         if (err)
  582.         {
  583.             *oldDataSize = collectSize;
  584.             *oldData = NewPtrSys(*oldDataSize);
  585.             if (!(err = MemError()))
  586.                 BlockMove(newData, *oldData, collectSize);
  587.         }
  588.         else
  589.         {
  590.             *oldData = NewPtrSys(*oldDataSize);
  591.             if (!(err = MemError()))
  592.                 err = GetCollectionItem(whichCollection,
  593.                                         collectType,
  594.                                         collectID,
  595.                                         dontWantSize,
  596.                                         *oldData);
  597.         }
  598.  
  599.         nrequire(err, CouldNotSetOldData);
  600.     }
  601.  
  602. /*
  603.     If we're adding a new collection item, do so.  Otherwise,
  604.     get the existing item's index and replace the old collection
  605.     item.
  606. */
  607.     err = AddCollectionItem(whichCollection,
  608.                             collectType,
  609.                             collectID,
  610.                             collectSize,
  611.                             newData);
  612.  
  613.     if (err == collectionItemLockedErr)
  614.     {
  615.         err = GetCollectionItemInfo(whichCollection,
  616.                                     collectType,
  617.                                     collectID,
  618.                                     &index,
  619.                                     dontWantSize,
  620.                                     dontWantAttributes);
  621.         if (!err)
  622.             err = ReplaceIndexedCollectionItem(whichCollection,
  623.                                                index,
  624.                                                collectSize,
  625.                                                newData);
  626.     }
  627.  
  628. CouldNotSetOldData:
  629.     return err;
  630. }
  631.